import { HttpError, WEBSOCKET, WEBSOCKETS, toSuccess, useTransaction, useEntityManager } from "@sker/core";
import { useData } from "@sker/runtime";
import { AutoDevice, AutoRed2, AutoTask, AutoTaskScript, AutoTaskScriptLog, AutoTaskScriptNotFound } from "@sker/entities";
import { DependencyContainer, container } from "tsyringe";
import { getTask, onConnection, runTask } from "./tasks/getTask";
import dayjs from "dayjs";
import { Between, LessThan, MoreThan } from "typeorm";

export default async (data: any) => {
    const { type, payload, injector } = data;
    if (!injector) {
        throw new HttpError(`参数错误`)
    }
    const socket = (injector as DependencyContainer).resolve(WEBSOCKET);
    Reflect.set(socket, 'pingTime', new Date().getTime());
    Reflect.set(socket, 'isAlive', true);
    if (type === 'connection') {
        console.log(`connection ${payload.uuid}`)
        await useTransaction(async m => {
            const device = await m.findOne(AutoDevice, { where: { device_uuid: payload.uuid } })
            const toSave = m.create(AutoDevice,{
                id: device?.id,
                device_uuid: payload.uuid,
                device_name: device?.device_name || '',
                status: `1`,
                ping_time: new Date(),
                token: device?.token || ''
            })
            await m.save(AutoDevice, toSave)
            return device;
        });
        Reflect.set(socket, 'uuid', payload.uuid)
        socket.on('close', async () => {
            await useTransaction(async m => {
                const device = await m.findOne(AutoDevice, { where: { device_uuid: payload.uuid } })
                if (!device) return;
                await m.update(AutoDevice, device.id, { status: `0`, ping_time: new Date() })
            });
        });
        /**
         * 执行任务
         */
        await onConnection(payload.uuid, socket)
        return;
    }
    if (type === 'message') {
        return handlerMessage(data.paylaod)
    }
    return toSuccess(true)
}

async function handlerMessage(payload: any) {
    const { type } = payload;
    const data = useData()
    const websockets = container.resolve(WEBSOCKETS)
    const uuid = data.uuid;
    const wss = websockets.get(uuid)
    if (!wss) return;
    if (type === 'ping') {
        await runTask(data.uuid, type, wss)
        return;
    }
    if (type === 'STATE_CHANGE') {
        const { uuid, currentActivity, currentPackage, task } = payload.payload;
        const wss = websockets.get(uuid)
        await useEntityManager(async m => {
            const autoTask = await m.findOne(AutoTask, { where: { name: task } })
            if (autoTask) {
                const autoTaskScript = await m.findOne(AutoTaskScript, { where: { package_name: currentPackage }, order: { display_order: 'asc' } })
                if (autoTaskScript) {
                    const autoTaskScriptLog = m.create(AutoTaskScriptLog, {
                        device_uuid: uuid,
                        script_name: autoTaskScript.name,
                        task_name: autoTaskScript.task_name,
                        package_name: autoTaskScript.package_name,
                        run_time: new Date()
                    });
                    const { id } = await m.save(AutoTaskScriptLog, autoTaskScriptLog)
                    wss.send(JSON.stringify({
                        type: `CLOUD_CODE`,
                        payload: {
                            id: id,
                            code: `((container, tokens, utils, record)=>{` + autoTaskScript?.code + `})`,
                            timeout: autoTaskScript.timeout
                        }
                    }))
                    return;
                } else {
                    // 未处理的任务
                    const item = await m.findOne(AutoTaskScriptNotFound, {
                        where: {
                            task_name: task,
                            package_name: currentPackage,
                        }
                    });
                    const notFoundTaskScript = m.create(AutoTaskScriptNotFound, {
                        id: item?.id,
                        task_name: task,
                        package_name: currentPackage,
                    });
                    await m.save(AutoTaskScriptNotFound, notFoundTaskScript)
                }
            } else {
                console.log({
                    uuid, currentActivity, currentPackage, task
                })
            }
        });
    }
    if (type === 'CLOUD_CODE_RETURN') {
        const { uuid, id, data, log } = payload.payload;
        if (id === `RUN_DEBUG_SCRIPT`) {
            // 调试信息 发送个调试器
            const socket = websockets.get(`RUN_DEBUG_SCRIPT`)
            socket.send(JSON.stringify({
                data, log, uuid, id, type: `CLOUD_CODE_RETURN`
            }));
            return;
        }
        await useEntityManager(async m => {
            await m.update(AutoTaskScriptLog, id, { result: data })
        });
        return;
    }
    if (type === 'CLOUD_DEBUG') {
        const { uuid, id, data, log } = payload.payload;
        const socket = websockets.get(`RUN_DEBUG_SCRIPT`)
        socket.send(JSON.stringify({
            data, log, uuid, id, type: `CLOUD_DEBUG`
        }));
    }
    if (type === 'CLOUD_CODE_ERROR') {
        const { uuid, id, data, log } = payload.payload;
        if (id === `RUN_DEBUG_SCRIPT`) {
            // 调试信息 发送个调试器
            const socket = websockets.get(`RUN_DEBUG_SCRIPT`)
            socket.send(JSON.stringify({
                data, log, uuid, id, type: `CLOUD_CODE_ERROR`
            }));
            return;
        }
        await useEntityManager(async m => {
            await m.update(AutoTaskScriptLog, id, { result: data })
        });
        return;
    }
    if (type === 'CLOUD_CODE_FINISH') {
        const { uuid, id, log, data } = payload.payload;
        if (id === `RUN_DEBUG_SCRIPT`) {
            // 调试信息 发送个调试器
            const socket = websockets.get(`RUN_DEBUG_SCRIPT`)
            socket.send(JSON.stringify({
                log, uuid, id, data, type: `CLOUD_CODE_FINISH`
            }));
            return;
        }
        await useEntityManager(async m => {
            await m.update(AutoTaskScriptLog, id, { finish_time: new Date() });
            // 继续执行其他任务
        });
        return;
    }
    if (type === 'GET_TASK') {
        return;
    }
    if (type === 'FIND_RED_PACKET') {
        // redPacketsList, maxCount, onLine, name, originLink, openTime
        const { redPacketsList, maxCount, onLine, name, originLink, openTime } = payload.payload;
        useEntityManager(async m => {
            const data = m.create(AutoRed2, {
                count: maxCount,
                online: onLine,
                name,
                link: originLink,
                open_time: openTime,
                redPackets: redPacketsList
            })
            await m.save(AutoRed2, data)
        })
        return;
    }
    if (type === 'GET_RED_ROOM') {
        const sendRedRoom = async () => {
            const result = await useEntityManager(async m => {
                const start = dayjs().add(30, 'second').toDate()
                const end = dayjs().add(60 * 2, 'second').toDate()
                const item = await m.findOne(AutoRed2, { where: { open_time: Between(start, end), count: MoreThan(60), join_count: LessThan(6) }, order: { count: 'desc', join_count: 'asc', open_time: 'asc' } })
                if (item) {
                    await m.update(AutoRed2, item.id, { join_count: item.join_count + 1 })
                    console.log(`发送给${uuid}一个红包`)
                    wss.send(JSON.stringify({ type: 'JOIN_RED_ROOM', payload: item }))
                    return true;
                }
                return false;
            });
            if (result) {
                return;
            } else {
                await new Promise<void>((resolve, reject) => {
                    setTimeout(() => {
                        resolve()
                    }, 5 * 1000)
                })
                return sendRedRoom()
            }
        }
        sendRedRoom();
        return;
    }
    const socket = websockets.get(`RUN_DEBUG_SCRIPT_TASK_FILE`)
    if (socket) {
        socket.send(JSON.stringify(payload));
    }
    await runTask(uuid, type, wss);
}
